#include "page_allocator.h"

#include <stdint.h>

#include <chrono>
#include <functional>
#include <set>
#include <thread>
#include <vector>

#include "../container/LinkList.h"
#include "../sync/lock.h"
#include "../time/time.h"

#ifndef BASSERT
#define BASSERT  // TODO
#endif           // !BASSERT

namespace qb {
namespace base {
class MemoryPage {
 public:
  enum {
    kPageGuard = 0xFE21FD31,  // MemoryPage的守卫值,前后都有
    kPageBits = 16,           //
    kPageSize = 1 << kPageBits,  // 每次分配内存尺寸的单位,以此整数倍来分配
  };

 protected:
  typedef unsigned char byte;
  MemoryPage* m_next;  // 双链表的下一个
  MemoryPage* m_prev;  // 双链表的的上一个
  uint32_t m_guard;    // 守卫值
  uint32_t m_tick;     // 创建后的时间
  int m_capcity;       // 当前页面的m_buffer总大小
  int m_offset;        // 下一次分配的偏移量
  int m_count;         // 已经分配了多少个
  byte* m_buffer;      // 指向紧跟当前类后面的内存
 private:
  MemoryPage() = delete;   // 此类不准创建
  ~MemoryPage() = delete;  // 此类不准创建
 public:
  static int GetStaticSize() { return sizeof(MemoryPage) + sizeof(uint32_t); }
  static bool CheckPage(const MemoryPage* page) {
    if (page == nullptr) return false;
    if (page->GetNext() != nullptr || page->GetPrev() != nullptr) return false;
    if (page->m_guard != kPageGuard) return false;
    const byte* buf = (const byte*)page + sizeof(MemoryPage);
    if (page->m_buffer != buf) return false;
    if (*((uint32_t*)(buf + page->m_capcity)) != kPageGuard) return false;
    if (page->m_offset < 0 || page->m_offset > page->m_capcity) return false;
    int size = MemoryPage::GetStaticSize() + page->m_capcity;
    if (size % MemoryPage::kPageSize != 0) return false;
    return true;
  }
  void Build(void* buffer, int size) {
    // 最开头和最末位都必须设定一个固定值
    BASSERT(buffer && size > 0 && size % MemoryPage::kPageSize == 0);
    m_prev = nullptr;
    m_next = nullptr;
    m_guard = kPageGuard;
    m_tick = GetTickCount();
    m_capcity = size - MemoryPage::GetStaticSize();
    m_offset = 0;
    m_count = 0;
    m_buffer = (byte*)buffer + sizeof(MemoryPage);
    // memset(m_buffer, 0, m_capcity);
    m_buffer[0] = '\0';  // 不做全部零初始化,开销大
    byte* pend = &((byte*)buffer)[size - sizeof(uint32_t)];
    *((uint32_t*)pend) = kPageGuard;
  }
  void SetNext(MemoryPage* next) {
    BASSERT(next != this);
    m_next = next;
  }
  void SetPrev(MemoryPage* prev) {
    BASSERT(prev != this);
    m_prev = prev;
  }
  MemoryPage* GetNext() const { return m_next; }
  MemoryPage* GetPrev() const { return m_prev; }
  int CountList() const {
    int ncout = 0;
    const MemoryPage* cur = this;
    while (cur) {
      ncout++;
      cur = cur->GetNext();
    }
    return ncout;
  }
  MemoryPage* Link(MemoryPage* page) {
    // 将page连接到当前后面
    BASSERT(page != nullptr && page->GetNext() == nullptr &&
            page->GetPrev() == nullptr);
    page->SetNext(m_next);
    page->SetPrev(this);
    if (m_next) m_next->SetPrev(page);
    m_next = page;
    return this;
  }
  MemoryPage* LinkBySpace(MemoryPage* page, int maxStep) {
    // 将page插入到当前双链表中,按照space递减排列,最多找maxStep次
    // 注意,不是严格递减,考虑到性能
    // 如果插入到开头,返回page,否则返回page之前的
    BASSERT(page != nullptr && page->GetNext() == nullptr &&
            page->GetPrev() == nullptr);
    int space = page->GetSpace();
    if (space >= GetSpace()) {
      // 大于当前的空余空间,已经在外面添加
      return nullptr;
    }
    MemoryPage* prev = this;
    MemoryPage* cur = GetNext();
    int i = 0;
    for (; i < maxStep; i++) {
      if (cur == nullptr || space >= cur->GetSpace()) {
        prev->Link(page);
        return prev;
      }
      prev = cur;
      cur = cur->GetNext();
    }
    prev->Link(page);
    return prev;
  }
  MemoryPage* Unlink() {
    // 从双链表中断开
    MemoryPage* prev = m_prev;
    if (m_prev) m_prev->SetNext(m_next);
    if (m_next) m_next->SetPrev(m_prev);
    m_next = nullptr;
    m_prev = nullptr;
    return prev;
  }

  void Reset() {
    BASSERT(m_buffer && GetTotalBytes() % kPageSize == 0);
    // memset(m_buffer, 0, m_capcity);
    m_buffer[0] =
        '\0';  // 较大范围的不必要的memset是性能瓶颈,保留脏数据,后续分配的时候清除
    m_guard = kPageGuard;
    // m_tick = GetTickCount();
    m_offset = 0;
    m_count = 0;
    byte* pend = &((byte*)m_buffer)[m_capcity];
    *((uint32_t*)pend) = kPageGuard;
  }
  inline void SetTick(uint32_t tick) { m_tick = tick; }
  inline uint32_t GetTick() const { return m_tick; }
  inline int GetTotalBytes() const {
    return m_capcity + MemoryPage::GetStaticSize();
  }
  inline int GetCapcity() const { return m_capcity; }
  inline int GetSpace() const { return m_capcity - m_offset; }
  void* Alloc(int bytes, int align = 4) {
    int offset = m_offset;
    if (offset % align != 0) offset = ((offset / align) + 1) * align;
    if (offset + bytes > m_capcity) return nullptr;
    void* ptr = m_buffer + offset;
    // memset(ptr, 0,
    // bytes);//为了性能,不初始化为0,外部有构造函数都会进一步初始化
    m_offset = offset + bytes;
    m_count++;
    return ptr;
  }
};

class CentralAllocator {  // 全局中央分配器
  enum {
    kMegaSize = 1024 * 1024,
    kMegaBits = 20,    // 1mb的比特位数
    kSlotCount = 256,  // 中央内存堆中哈希表的尺寸,不宜过大
    kCacheGB = 1024,   // 1024mb
    kCacheMax =
        256,  // 当缓存多余此值时,释放页面时,立即释放给系统而不是放入缓存
    kCacheCheck = 128,  // 当缓存多余此值时,触发自动清除检查
    kCacheMin = 64,  // 当缓存低于此值时,终止之前触发的自动清除检查
    kCacheLife =
        1 * 60 *
        1000,  // 一个缓存的最大生命周期,1分钟,超过此值在检查阶段可能被删除
    kCheckInterval = 1000,  // 检查阶段,每间隔多少毫秒钟检测一次
    kShortLife = 4000,  // 小于此值的算短生命周期,其页面释放优先进入缓存
    kMaxShortCount = 1024,  // 短生命周期的页面个数
    kCheckMaxTime = 20,     // 每次最多检查多少毫秒
    kRemoveTimes = 20       // 每次最多删除多少个
  };
  static_assert(kCacheMin < kCacheCheck,
                "kCacheMin must be smaller than kCacheCheck");
  static_assert(kCacheCheck < kCacheMax,
                "kCacheCheck must be smaller than kCacheMax");
  // 全局中央分配器,多个线程同步

  typedef std::set<MemoryPage*> MemoryPageSet;
  typedef std::set<PageAllocator*> AllocatorSet;

 protected:
  CSLock m_lock;
  DoubleLinkList<MemoryPage>
      m_slots[kSlotCount];  // <=1mb的双链表,位于某个index的MemoryPage,其尺寸
  // 是kPageSize的(index+1)倍
  // 最末尾的尺寸为kPageSize*kSlotCount,最大4mb
  int64_t m_allocated_bytes;  // 已经分配的,供外部使用的所有内存总数
  int64_t m_cached_bytes;  // 留在m_slots中缓存的所有内存总数
  uint32_t m_lasttick;     // 上一次检查的时间
  int m_lastslot;  // 上一次检查的插槽,每次检查都沿着上一次检查的位置进行下去
  int64_t m_deepcopy_count;  // 深度拷贝的总次数
  double m_deepcopy_time;    // 深度拷贝的总时间
  MemoryPageSet* m_allocated;  // 已经分配的共外部使用的页面集合,用于调试
  AllocatorSet m_allocators;  // 所有的Allocator;
  uint32_t m_last_time;       // 上一次
  std::thread* m_thread;
  bool m_track_allocators;  //
  bool
      m_check_dirty;  // 当全部检查完毕,不需要反复扫描检查;只要缓存中有新增,立刻为true;
  bool m_exit = false;

 private:
  CentralAllocator()
      : m_allocated_bytes(0),
        m_cached_bytes(0),
        m_lastslot(0),
        m_lasttick(0),
        m_allocated(nullptr),
        m_track_allocators(false),
        m_last_time(0),
        m_deepcopy_count(0),
        m_deepcopy_time(0),
        m_check_dirty(false) {
    m_thread = new std::thread(std::bind(&CentralAllocator::runCheck, this));
  }
  static void runCheck(CentralAllocator* ca) {
    int64_t wait_time = 1000;
    try {
      while (true) {
        if (ca->m_exit) return;
        std::this_thread::sleep_for(std::chrono::milliseconds(wait_time));
        wait_time = ca->CheckPageDynamicly() ? 1000 : 20;
        std::this_thread::yield();
      }
    } catch (...) {
    }
  }
  ~CentralAllocator() {
    m_exit = true;
    m_thread->join();
    ScopedLock<CSLock> _scoped(m_lock);  // 同步
    for (int i = 0; i < kSlotCount; i++) {
      while (MemoryPage* cur = m_slots[i].PickHead()) {
        FreeMemory(cur);
      }
    }
  }
  int64_t GetCachedBytes() {
    ScopedLock<CSLock> _scoped(m_lock);
    return m_cached_bytes;
  }

 public:
  bool CheckPageDynamicly() {
    /*
    当m_cached_bytes 越大越偏离kCacheCheck,释放的越快
    当m_cached_bytes 越靠近kCacheCheck, 释放的越慢
    限制每一次调用的作用时间不超过kCheckMaxTime
    设定3个节点:其他的按照线性插值
    kCacheCheck		1
    kCacheMax		30mb
    1gb				100mb
    */
    static_assert(kCacheMax > kCacheCheck && kCacheGB > kCacheMax,
                  "kCacheMax > kCacheCheck && kCacheGB > kCacheMax failed");
    const double check_bytes = 1;
    const double max_bytes = 30;
    const double gb_bytes = 100;
    int64_t cache = GetCachedBytes() >> kMegaBits;
    double mgbytes = check_bytes;
    if (cache <= kCacheCheck) return true;

    if (cache < kCacheMax)
      mgbytes = 1.0 * (cache - kCacheCheck) * (max_bytes - check_bytes) /
                    (kCacheMax - kCacheCheck) +
                check_bytes;
    else if (cache < kCacheGB)
      mgbytes = 1.0 * (cache - kCacheMax) * (gb_bytes - max_bytes) /
                    (kCacheGB - kCacheMax) +
                max_bytes;
    else
      mgbytes = gb_bytes;
    mgbytes = mgbytes * kMegaSize;

    // 找到最老的一个插槽
    uint32_t tick = GetTickCount();
    if (m_exit) return true;

    int sum_bytes = 0;
    int check_count = 0;
    while (true) {
      int bytes = CheckOldestPage();
      if (bytes <= 0) break;
      sum_bytes += bytes;
      check_count++;
      if (sum_bytes > mgbytes || GetTickCount() - tick > kCheckMaxTime) break;
    }
    if (cache <= kCacheCheck || sum_bytes >= mgbytes) return true;
    return false;
  }
  int CheckOldestPage() {
    int index = -1;
    int bytes = 0;
    uint32_t tick = 0;
    MemoryPage* page = nullptr;
    {
      ScopedLock<CSLock> _scoped(m_lock);
      for (int i = 0; i < kSlotCount; i++) {
        DoubleLinkList<MemoryPage>& pinfo = m_slots[i];
        MemoryPage* temp = pinfo.GetTail();
        if (temp == nullptr) continue;
        if (index >= 0 && temp->GetTick() >= tick) continue;
        tick = (index < 0 || temp->GetTick() < tick) ? temp->GetTick() : tick;
        index = i;
      }
      if (index >= 0) {
        DoubleLinkList<MemoryPage>& pinfo = m_slots[index];
        if (pinfo.GetTail()) {
          page = pinfo.PickTail();
          bytes = page->GetTotalBytes();
          m_cached_bytes -= bytes;
        }
      }
    }

    // 将FreeMemory放在锁外面,缩短锁的时间
    if (page) FreeMemory(page);
    return bytes;
  }
  static CentralAllocator& Get() {
    static CentralAllocator central_allocator;
    return central_allocator;
  }
  PageAllocator* CreateAllocator(const PageAllocator::RootPtrType root,
                                 bool inMessage);
  void DestroyAllocator(PageAllocator* allocator);

  MemoryPage* AllocPage(int bytes) {
    int pagewasted = MemoryPage::GetStaticSize();  // 末尾Guard
    int index = ((bytes + pagewasted) >> MemoryPage::kPageBits);
    MemoryPage* page = nullptr;
    if (index < kSlotCount) {
      ScopedLock<CSLock> _scoped(m_lock);  // 同步
      for (int i = 0; i < 2 && index + i < kSlotCount; i++) {
        int slot = index + i;
        DoubleLinkList<MemoryPage>& pi = m_slots[slot];
        if (pi.GetHead() && pi.GetHead()->GetCapcity() >= bytes) {
          page = pi.PickHead();
          page->Reset();
          m_cached_bytes -= page->GetTotalBytes();
          m_allocated_bytes += page->GetTotalBytes();
          break;
        }
      }
      if (page && m_allocated) m_allocated->insert(page);
    }

    bool allocnew = false;
    if (page == nullptr) {
      allocnew = true;
      int size = (index + 1) * MemoryPage::kPageSize;
      char* buf = (char*)MallocMemory(size);
      page = (MemoryPage*)buf;
      page->Build(buf, size);
      page->SetNext(nullptr);
      page->SetPrev(nullptr);
      {
        ScopedLock<CSLock> _scoped(m_lock);
        m_allocated_bytes += page->GetTotalBytes();
        if (page && m_allocated) m_allocated->insert(page);
      }
    }
    BASSERT(page && page->GetNext() == nullptr && page->GetPrev() == nullptr);

    // 当缓存池大小
    if (allocnew || (m_cached_bytes >> kMegaBits) >= kCacheCheck) {
      CheckOldPage();
    }
    return page;
  }
  void FreePage(MemoryPage* page, bool force = false) {
    if (page == nullptr) return;
    BASSERT(page->GetNext() == nullptr && page->GetPrev() == nullptr);
    BASSERT(page->GetTotalBytes() % MemoryPage::kPageSize == 0);
    int slot = page->GetTotalBytes() >> MemoryPage::kPageBits;
    uint32_t tick = GetTickCount();
    ScopedLock<CSLock> _scoped(m_lock);
    m_allocated_bytes -= page->GetTotalBytes();
    if (m_allocated) {
      MemoryPageSet::iterator it = m_allocated->find(page);
      if (it != m_allocated->end()) m_allocated->erase(it);
    }

    // 当page为1个单位且是最近分配的时候,通常是栈上Message临时分配使用
    // 这样的Message会在栈上频繁反复的构造,导致此种情况非常频繁,需要特殊优化
    if (force) {
      BASSERT(MemoryPage::CheckPage(page));
      FreeMemory(page);
    } else if ((slot == 1 && tick - page->GetTick() < kShortLife &&
                m_slots[slot].GetCount() <= kMaxShortCount) ||
               slot < kSlotCount || (m_cached_bytes >> kMegaBits) < kCacheMax) {
      page->Reset();
      m_slots[slot].InsertHead(page);
      BASSERT(m_slots[slot].GetHead() == page && page->GetPrev() == nullptr);
      m_cached_bytes += page->GetTotalBytes();
      m_check_dirty = true;
    } else {
      BASSERT(MemoryPage::CheckPage(page));
      FreeMemory(page);
    }
  }
  void CheckOldPage() {
    // 间隔删除长时间不用的缓存页面
    uint32_t tick = GetTickCount();
    MemoryPage* head = nullptr;
    // if (tick > m_lasttick + kCheckInterval)
    {
      ScopedLock<CSLock> _scoped(m_lock);
      // m_lasttick = tick;
      int nremoved = 0;
      for (int i = 0; i < kSlotCount; i++) {
        m_lastslot = (m_lastslot + 1) % kSlotCount;
        DoubleLinkList<MemoryPage>& pinfo = m_slots[m_lastslot];
        MemoryPage* page = pinfo.GetTail();
        if (page && tick > page->GetTick() + kCacheLife) {
          page = pinfo.PickTail();
          m_cached_bytes -= page->GetTotalBytes();
          if (head == nullptr)
            head = page;
          else
            head->Link(page);
          nremoved++;
        }
        if (nremoved >= kRemoveTimes || GetTickCount() > tick + kCheckMaxTime ||
            (m_cached_bytes >> kMegaBits) < kCacheMin)
          break;
      }
    }
    while (head) {
      MemoryPage* next = head->GetNext();
      FreeMemory(head);
      head = next;
    }
  }
  void AddDeepCopyCount(double time) {
    if (!m_track_allocators) return;
    ScopedLock<CSLock> _scoped(m_lock);
    m_deepcopy_count++;
    m_deepcopy_time += time;
  }

 protected:
  void TrackAllocator(PageAllocator* allocator, bool add);
  int GetTotalCount() const {
    int ntotal = 0;
    for (int i = 0; i < kSlotCount; i++) {
      ntotal += m_slots[i].GetCount();
    }
    return ntotal;
  }
  void DumpStatus() {
    int ntotal = GetTotalCount();
    int nactive = m_allocated ? (int)m_allocated->size() : 0;
    // char buf[1024] = { 0 };
    // BVIEW("[SDBUS][CentralAllocator]cached:%I64d allocated:%I64d  total:%I64d
    // count:%6d active:%6d", m_cached_bytes, 	m_allocated_bytes, m_totalbytes,
    //GetTotalCount(), nactive);
  }
  void* MallocMemory(int bytes) { return ::malloc(bytes); }
  void FreeMemory(MemoryPage* page) {
    if (page) {
      ::free((char*)page);
    }
  }
};

class MemoryPageList {
  enum {
    kSpaceGap = 128,  // 空余空间按照此数值来分组到若干个双链表中
    kSpaceSlot = 32,  // 总共有多少个空余的双链表
    kSpaceMin =
        16,  // 当MemoryPage末尾空余小于16字节,忽略,放入m_full中,值越大,浪费越多,性能越好
    kMaxLinkStep = 64  // 最大连接次数,值越大,LinkBySpace耗时越长,效果越好
  };
  static_assert(kSpaceSlot == sizeof(unsigned int) * 8,
                "kSpaceSlot must be sizeof(unsingned int)");
  DoubleLinkList<MemoryPage> m_head[kSpaceSlot];  // 有空闲内存空间的双链表
  // 索引值越大,空闲空间越多
  // index*kSpaceGap<=空闲空间<(index+1)*kSpaceGap
  MemoryPage* m_full;  // 已经满的双链表
  int m_full_count;    // 已经满的双链表里的MemoryPage个数
  int m_total_bytes;   // 总体累积内存
  int m_total_count;
  bool m_force_free;

 public:
  MemoryPageList(bool force)
      : m_full(nullptr),
        m_full_count(0),
        m_total_bytes(0),
        m_total_count(0),
        m_force_free(force) {}
  ~MemoryPageList() { Release(); }
  int GetBytes() const { return m_total_bytes; }
  void AddPage(MemoryPage* page) {
    // 待加入的page必须是孤立的MemoryPage
    BASSERT(page && page->GetNext() == nullptr && page->GetPrev() == nullptr);
    AddPageImpl(page);
    m_total_bytes += page->GetTotalBytes();
    m_total_count++;
  }
  void* Alloc(int bytes) {
    int slot = bytes / kSpaceGap;
    slot = slot >= kSpaceSlot ? (kSpaceSlot - 1) : slot;
    for (int i = slot; i < kSpaceSlot; i++) {
      MemoryPage* head = m_head[i].GetHead();
      void* ptr = head ? head->Alloc(bytes) : nullptr;
      if (ptr) {
        BASSERT(head && head->GetPrev() == nullptr);
        head = m_head[i].PickHead();
        AddPageImpl(head);
        return ptr;
      }
    }
    return nullptr;
  }
  int Release() {
    int ncount = ReleaseList(m_full);
    m_full = nullptr;
    m_full_count = 0;
    for (int i = 0; i < kSpaceSlot; i++) {
      DoubleLinkList<MemoryPage>& mslot = m_head[i];
      int count = mslot.GetCount();
      while (MemoryPage* head = mslot.PickHead()) {
        CentralAllocator::Get().FreePage(head, m_force_free);
      }
      ncount += count;
    }
    BASSERT(ncount == m_total_count);
    m_total_count = 0;
    return ncount;
  }

 protected:
  void CheckAll() {
    return;
    std::vector<MemoryPage*> pages;
    int ncount = m_full ? m_full->CountList() : 0;
    for (int i = 0; i < kSpaceSlot; i++) {
      DoubleLinkList<MemoryPage>& mslot = m_head[i];
      int acount = mslot.GetCount();
      MemoryPage* head = mslot.GetHead();
      if (head) {
        pages.clear();
        pages.reserve(acount);
        for (int k = 0; k < acount; k++) {
          if (head) pages.push_back(head);
          BASSERT(head);
          head = head->GetNext();
        }
      }
      ncount += acount;
    }
    // BASSERT(ncount == m_total_count);
  }
  void AddPageImpl(MemoryPage* page) {
    BASSERT(page && page->GetNext() == nullptr && page->GetPrev() == nullptr);
    int space = page->GetSpace();
    if (space <= kSpaceMin) {
      if (m_full)
        m_full->Link(page);
      else
        m_full = page;
      m_full_count++;
    } else {
      // 如果空闲空间非常多,将其加到最末一个双链表开头
      // 将page按照其空闲空间的多少放到合适的双链表中
      int slot = space / kSpaceGap;
      if (slot >= kSpaceSlot) slot = kSpaceSlot - 1;
      DoubleLinkList<MemoryPage>& mslot = m_head[slot];
      mslot.InsertBySpace(page, kMaxLinkStep);
    }
  }
  int ReleaseList(MemoryPage* head) {
    int ncount = 0;
    while (head) {
      MemoryPage* cur = head;
      head = head->GetNext();
      cur->SetNext(nullptr);
      cur->SetPrev(nullptr);
      CentralAllocator::Get().FreePage(cur, m_force_free);
      ncount++;
    }
    return ncount;
  }
};

/////////////////////////////////////////////////////////////////////////////
PageAllocator* CentralAllocator::CreateAllocator(
    const PageAllocator::RootPtrType root, bool inMessage) {
  PageAllocator* a = new PageAllocator(root, inMessage);
  if (m_track_allocators && inMessage) TrackAllocator(a, true);
  return a;
}
void CentralAllocator::DestroyAllocator(PageAllocator* allocator) {
  if (allocator) {
    if (m_track_allocators) TrackAllocator(allocator, false);
    delete allocator;
  }
}
void CentralAllocator::TrackAllocator(PageAllocator* allocator, bool add) {
  if (allocator == nullptr) return;
  ScopedLock<CSLock> _scoped(m_lock);
  if (add) {
    AllocatorSet::iterator it = m_allocators.find(allocator);
    if (it != m_allocators.end()) {
      // BVIEW("[SDBUS]Allocator:0x%8x already exist", allocator);
    }
    m_allocators.insert(allocator);
  } else {
    AllocatorSet::iterator it = m_allocators.find(allocator);
    if (it == m_allocators.end()) {
      // if (allocator->IsInMessage())
      // BVIEW("[SDBUS]Allocator:0x%8x does not exist", allocator);
    } else
      m_allocators.erase(it);
  }
  uint32_t tick = GetTickCount();
  if (tick > m_last_time + 5000) {
    m_last_time = tick;
    /*
    BVIEW("[SDBUS]pid:%8d current messages:%6d total bytes:%I64d = %6.3fmb cache
    bytes:%I64d = %6.3fmb deepcopy:%I64d each:%8.0fus slot[1]:%d",
            GetCurrentProcessId(),
            m_allocators.size(),
            m_allocated_bytes, m_allocated_bytes*1.0 / 1024 / 1024,
            m_cached_bytes, m_cached_bytes*1.0 / 1024 / 1024,
            m_deepcopy_count,
            m_deepcopy_count == 0 ? 0 : (m_deepcopy_time / m_deepcopy_count),
            m_slots[1].GetCount()
            );
            */
  }
}

//////////////////////////////////////////////////////////////////////////

void* PageAllocator::AllocMemory(int bytes) {
  // 总是取最后一个
  // 如果bytes非常大,超过4kb怎么办?
  // 如果末尾有空余空间怎么办?
  // 挑选一个内存页
  // 默认总是从最后面挑选
  // 当最后一个页面无法分配给定尺寸的内存的时候
  // 看当前所有页面的最大空余空间的页面
  // 空余内容小于给定阀值,就忽略,为了性能
  // 兼顾总内存占用和整体性能
  // double cur = GetHighResTimeD();
  void* ptr = m_current ? m_current->Alloc(bytes)
                        : (m_pagelist ? m_pagelist->Alloc(bytes) : nullptr);
  if (ptr == nullptr) {
    if (m_pagelist == nullptr) m_pagelist = new MemoryPageList(m_force_free);
    if (m_current) m_pagelist->AddPage(m_current);
    m_current = CentralAllocator::Get().AllocPage(bytes);
    BASSERT(m_current && m_current->GetNext() == nullptr &&
            m_current->GetPrev() == nullptr);
    ptr = m_current->Alloc(bytes);
    BASSERT(ptr != nullptr);
  }
  // m_alloc_time += GetHighResTimeD() - cur;
  return ptr;
}

PageAllocator::PageAllocator(const RootPtrType vmap, bool inMessage)
    : m_root(vmap),
      m_current(nullptr),
      m_central(nullptr),
      m_inmsg(inMessage),
      m_alloc_time(0.0),
      m_pagelist(nullptr),
      m_force_free(true) {
  m_central = &CentralAllocator::Get();
}

PageAllocator::~PageAllocator() {
  // double cur = GetHighResTimeD();
  if (m_current) {
    BASSERT(m_current && m_current->GetNext() == nullptr &&
            m_current->GetPrev() == nullptr);
    CentralAllocator::Get().FreePage(m_current, m_force_free);
  }
  m_current = nullptr;
  if (m_pagelist) {
    m_pagelist->Release();
    delete m_pagelist;
    m_pagelist = nullptr;
  }
  // double freetime = GetHighResTimeD()-cur;
  // BVIEW("Allocator alloctime:%8dus  freetime:%8dus  count:%8d",
  //	(unsigned int)m_alloc_time, (unsigned int)freetime,ncount);
}

PageAllocator* PageAllocator::CreateWithRoot(RootPtrType root, bool inMessage) {
  return CentralAllocator::Get().CreateAllocator(root, inMessage);
}

void PageAllocator::Destroy(PageAllocator* allocator) {
  CentralAllocator::Get().DestroyAllocator(allocator);
}

void PageAllocator::SwapRoot(PageAllocator* dest, PageAllocator* source) {
  if (dest == nullptr && source == nullptr) return;
  const RootPtrType v1 = dest ? dest->GetRoot() : nullptr;
  const RootPtrType v2 = source ? source->GetRoot() : nullptr;
  if (dest) dest->m_root = v2;
  if (source) source->m_root = v1;
}

int PageAllocator::GetBytes() const {
  int bytes = sizeof(PageAllocator);
  if (m_current) bytes += m_current->GetTotalBytes();
  bytes += m_pagelist ? m_pagelist->GetBytes() : 0;
  return bytes;
}

}  // namespace base
}  // namespace qb
